home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / mint104s.zoo / mint.src / tty.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  19KB  |  803 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * read/write routines for TTY devices
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. static void _erase P_((FILEPTR *, int));
  14. static int escseq P_((struct tty *, int));
  15.  
  16. /* setting a special character to this value disables it */
  17. #define UNDEF 0
  18.  
  19.  
  20. /* default terminal characteristics */
  21.  
  22. struct tty default_tty = {
  23.     0,            /* process group */
  24.     0,            /* state */
  25.     0,            /* use_cnt */
  26.     0,            /* reserved short */
  27.     {
  28.     13, 13,            /* input speed == output speed == 9600 baud */
  29.     CTRL('H'),        /* erase */
  30.     CTRL('U'),        /* kill */
  31.     T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */
  32.     },
  33.     {
  34.     CTRL('C'),        /* interrupt */
  35.     CTRL('\\'),        /* quit */
  36.     CTRL('Q'),        /* start */
  37.     CTRL('S'),        /* stop */
  38.     CTRL('D'),        /* EOF */
  39.     '\r'            /* alternate end of line */
  40.     },
  41.     {
  42.     CTRL('Z'),        /* suspend */
  43.     CTRL('Y'),        /* suspend after read */
  44.     CTRL('R'),        /* reprint */
  45.     UNDEF,            /* flush output */
  46.     CTRL('W'),        /* erase word */
  47.     CTRL('V')        /* quote next char */
  48.     },
  49.     {
  50.     0, 0, 0, 0        /* window size is unknown */
  51.     },
  52.     0,            /* no process is selecting us for reading */
  53.     0,            /* or for writing */
  54.     0            /* use default XKEY map */
  55. };
  56.  
  57. #define _put(f, c) (tty_putchar((f), (c), RAW))
  58.  
  59. static void
  60. _erase(f, c)
  61.     FILEPTR *f;
  62.     int c;
  63. {
  64.     _put(f, '\010');
  65.     _put(f, ' ');
  66.     _put(f, '\010');
  67. /* watch out for control characters -- they're printed as e.g. "^C" */
  68. /* BUG: \t is messed up. We really need to keep track of the output
  69.  * column
  70.  */
  71.     if (c >= 0 && c < ' ' && c != '\t') {
  72.         _put(f, '\010'); _put(f, ' '); _put(f, '\010');
  73.     }
  74. }
  75.  
  76. #define put(f, c)   { if (mode & T_ECHO) _put(f, c); }
  77. #define erase(f, c) { if (mode & T_ECHO) _erase(f, c); }
  78.  
  79. long
  80. tty_read(f, buf, nbytes)
  81.     FILEPTR *f;
  82.     void *buf;
  83.     long nbytes;
  84. {
  85.     long r;
  86.     long bytes_read = 0;
  87.     unsigned char ch, *ptr;
  88.     int rdmode, mode;
  89.     struct tty *tty;
  90.  
  91.     tty = (struct tty *)f->devinfo;
  92.     assert(tty != 0);
  93.  
  94.     if (f->flags & O_HEAD) {    /* pty server side? */
  95.         rdmode = RAW;        /* yes -- always raw mode */
  96.         mode = T_RAW;
  97.     }
  98.     else if (curproc->domain == DOM_MINT) {    /* MiNT domain process? */
  99.         mode = tty->sg.sg_flags;
  100.         rdmode = COOKED|NOECHO;
  101.         if ( mode & (T_RAW | T_CBREAK) ) {
  102.             rdmode = (mode & T_RAW) ? RAW : COOKED;
  103.         }
  104.         if (mode & T_XKEY)
  105.             rdmode |= ESCSEQ;
  106.     }
  107.     else {
  108.         rdmode = COOKED|NOECHO;
  109.         mode = T_TOS | T_ECHO;
  110.     }
  111.  
  112.     ptr = buf;
  113.  
  114.     while (bytes_read < nbytes) {
  115.         r = tty_getchar(f, rdmode);
  116.         if (r < 0) {
  117. tty_error:
  118.             DEBUG(("tty_read: tty_getchar returned %ld", r));
  119.             return (bytes_read) ? bytes_read : r;
  120.         }
  121.         else if (r == MiNTEOF)
  122.             return bytes_read;
  123.         ch = r & 0xff;
  124.  
  125.         if ( (mode & T_CRMOD) && (ch == '\r') )
  126.             ch = '\n';
  127.  
  128. /* 1 character reads in TOS mode are always raw */
  129.         if (nbytes == 1 && (mode & T_TOS)) {
  130.             put(f, ch);
  131.             *ptr = ch;
  132.             return 1;
  133.         }
  134.  
  135. /* T_CBREAK mode doesn't do erase or kill processing */
  136. /* also note that setting a special character to UNDEF disables it */
  137.  
  138.         if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
  139.             if ((char)ch == tty->sg.sg_erase) {  /* backspace */
  140.                 if (bytes_read > 0) {
  141.                     --ptr;
  142.                     erase(f, *ptr);
  143.                     bytes_read--;
  144.                 }
  145.                 continue;
  146.             }
  147.             else if ((mode & T_TOS) && ch == CTRL('X')) {
  148.                 while (bytes_read > 0) {
  149.                     --ptr;
  150.                     erase(f, *ptr);
  151.                     bytes_read--;
  152.                 }
  153.                 continue;
  154.             }
  155.             else if ((char)ch ==tty->ltc.t_rprntc || 
  156.                  (char)ch == tty->sg.sg_kill) {
  157.                 if (mode & T_TOS)
  158.                     put(f, '#');
  159.                 put(f, '\r');
  160.                 put(f, '\n');
  161.                 ptr = buf;
  162.                 if ((char)ch == tty->sg.sg_kill) {
  163.                     bytes_read = 0;
  164.                 }
  165.                 else {
  166.                     for (r = 0; r < bytes_read; r++, ptr++)
  167.                         put(f, *ptr);
  168.                 }
  169.                 continue;
  170.             }
  171.             else if ((char)ch == tty->ltc.t_werasc) {
  172.                 while (bytes_read > 0 &&
  173.                        !(ptr[-1] == ' ' || ptr[-1] == '\t')) {
  174.                     ptr--;
  175.                     erase(f, *ptr);
  176.                     bytes_read--;
  177.                 }
  178.                 continue;
  179.             }
  180.             else if ((char)ch == tty->ltc.t_lnextc) {
  181.                 put(f, '^');
  182.                 put(f, '\b');
  183.                 r = tty_getchar(f, RAW);
  184.                 if (r < 0)
  185.                     goto tty_error;
  186.                 else if (r == MiNTEOF)
  187.                     return bytes_read;
  188.                 ch = r & 0xff;
  189.                 goto stuff_it;
  190.             }
  191.             else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
  192.                 return bytes_read;
  193.         }
  194.  
  195. /* both T_CBREAK and T_COOKED modes have to do signals, though */
  196.         if ((rdmode & COOKED) && ch != UNDEF) {
  197.             if ((char)ch == tty->tc.t_intrc
  198.                  || (char)ch == tty->tc.t_quitc
  199.                  || (char)ch == tty->ltc.t_dsuspc
  200.                  || (char)ch == tty->ltc.t_suspc
  201.                 ) {
  202. /* the device driver raised the appropriate signal; if we get here, the
  203.    signal was caught by the user (or ignored). flush buffers and continue
  204.  */
  205.                 if (!(tty->sg.sg_flags & T_NOFLSH)) {
  206.                     DEBUG(("tty_read: flushing input"));
  207.                     bytes_read = 0;
  208.                     ptr = buf;
  209.                 }
  210.                 continue;
  211.             }
  212.             else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
  213.                 put(f, '\r');
  214.                 if (!(mode & T_TOS)) {
  215.                     *ptr = ch;
  216.                     put(f, '\n');
  217.                     bytes_read++;
  218.                 }
  219.                 return bytes_read;
  220.             }
  221.  
  222.         }
  223.  
  224. /* do the following for both RAW and COOKED mode */
  225. stuff_it:
  226.         *ptr++ = ch;
  227.         if (ch < ' ' && ch != '\t') {    /* ch is unsigned */
  228.             put(f, '^'); put(f, ch+'@');
  229.         }
  230.         else
  231.             put(f, ch);
  232.         bytes_read++;
  233.  
  234. /* for RAW mode, if there are no more characters then break */
  235.         if ( (mode & (T_RAW|T_CBREAK)) &&
  236.             !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
  237.             r = 1;
  238.             (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  239.             if (r <= 0) break;
  240.         }    
  241.     }
  242.  
  243.     return bytes_read;
  244. }
  245.  
  246. long
  247. tty_write(f, buf, nbytes)
  248.     FILEPTR *f;
  249.     const void *buf;
  250.     long nbytes;
  251. {
  252.     unsigned const char *ptr;
  253.     long c;
  254.     long bytes_written;
  255.     int mode, rwmode;
  256.     struct tty *tty;
  257.     int use_putchar = 0;
  258.     static long cr_char = '\r';
  259. #define LBUFSIZ 128
  260.     long lbuf[LBUFSIZ];
  261.  
  262.     tty = (struct tty *)f->devinfo;
  263.     assert(tty != 0);
  264.  
  265.     ptr = buf;
  266.     if (f->flags & O_HEAD) {
  267.         use_putchar = 1;
  268.         mode = T_RAW;
  269.     }
  270.     else if (curproc->domain == DOM_TOS)
  271. /* for TOS programs, 1 byte writes are always in raw mode */
  272.         mode = (nbytes == 1) ? T_RAW : T_TOS;
  273.     else
  274.         mode = tty->sg.sg_flags;
  275.  
  276.     rwmode = (mode & T_RAW) ? RAW : COOKED;
  277.  
  278.     bytes_written = 0;
  279.  
  280. /*
  281.  * "mode" can now be reduced to just T_CRMODE or not
  282.  */
  283.     if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
  284.         !(mode & T_RAW))
  285.         mode = T_CRMOD;
  286.     else
  287.         mode = 0;
  288.  
  289. /*
  290.  * we always write at least 1 byte with tty_putchar, since that takes
  291.  * care of job control and terminal states. After that, we may be able
  292.  * to use (*f->dev->write) directly.
  293.  */
  294.  
  295.  
  296.     if (nbytes == 0) return bytes_written;
  297.     c = *ptr++;
  298.  
  299.     if (c == '\n' && mode) {    /* remember, "mode" now means CRMOD */
  300.         tty_putchar(f, cr_char, rwmode);
  301.     }
  302.     tty_putchar(f, c, rwmode);
  303.     nbytes--;
  304.     bytes_written++;
  305.  
  306.     if (use_putchar) {
  307.         while (nbytes-- > 0) {
  308.             c = *ptr++;
  309.             if (c == '\n' && mode)
  310.                 tty_putchar(f, cr_char, rwmode);
  311.             tty_putchar(f, c, rwmode);
  312.             bytes_written++;
  313.         }
  314.     } else {
  315. /* write in big chunks if possible; but never more than 1 line
  316.  * (so that ^S/^Q can happen reasonably quickly for the user)
  317.  */
  318.         long bytes_to_write = 0;
  319.         long *s = lbuf;
  320.  
  321.         while (nbytes-- > 0) {
  322.             c = *ptr++;
  323.             if (c == '\n') {
  324.                 if (bytes_to_write) {
  325.                     (*f->dev->write)(f, (char *)lbuf,
  326.                         bytes_to_write);
  327.                     bytes_to_write = 0;
  328.                     s = lbuf;
  329.                 }
  330.                 if (mode)    /* i.e. T_CRMODE */
  331.                     tty_putchar(f, cr_char, rwmode);
  332.                 tty_putchar(f, (long)c, rwmode);
  333.                 bytes_written++;
  334.             } else {
  335.                 *s++ = c;
  336.                 bytes_written++;
  337.                 bytes_to_write += 4;
  338.                 if (bytes_to_write >= LBUFSIZ*4) {
  339.                     (*f->dev->write)(f, (char *)lbuf,
  340.                              bytes_to_write);
  341.                     bytes_to_write = 0;
  342.                     s = lbuf;
  343.                 }
  344.             }
  345.         }
  346.         if (bytes_to_write) {
  347.             (*f->dev->write)(f, (char *)lbuf, bytes_to_write);
  348.         }
  349.     }
  350.  
  351.     return bytes_written;
  352. }
  353.  
  354. /* some notable scan codes */
  355. #define K_INSERT    0x52
  356. #define K_HOME        0x47
  357. #define K_UNDO        0x61
  358. #define K_HELP        0x62
  359. #define CURS_UP        0x48
  360. #define CURS_DN        0x50
  361. #define CURS_RT        0x4d
  362. #define CURS_LF        0x4b
  363. #define F_1        0x3b